<?php
/**
 * | ---------------------------------------------------------------------------------------------------
 * | Author：johnxu <fsyzxz@163.com>.
 * | ---------------------------------------------------------------------------------------------------
 * | Home: https://www.johnxu.net.
 * | ---------------------------------------------------------------------------------------------------
 * | Data: 2018/12/30
 * | ---------------------------------------------------------------------------------------------------
 * | Desc: 优化的websocket基础类库
 * | ---------------------------------------------------------------------------------------------------
 */

class WebSocket
{
    const HOST = '0.0.0.0';
    const PORT = 8888;

    /**
     * @var swoole_websocket_server
     */
    private $ws;

    public function __construct()
    {
        $this->ws = new swoole_websocket_server( self::HOST, self::PORT );

        $this->set();

        $this->ws->listen( self::HOST, '8822', SWOOLE_SOCK_TCP );

        $this->ws->on( 'start', array( $this, 'onStart' ) );
        $this->ws->on( 'open', array( $this, 'onOpen' ) );
        $this->ws->on( 'message', array( $this, 'onMessage' ) );
        $this->ws->on( 'WorkerStart', array( $this, 'onWorkerStart' ) );
        // 添加任务
        $this->ws->on( 'task', array( $this, 'onTask' ) );
        $this->ws->on( 'finish', array( $this, 'onFinish' ) );
        $this->ws->on( 'close', array( $this, 'onClose' ) );
        $this->ws->on( 'request', array( $this, 'onRequest' ) );

        $this->ws->start();
    }

    /**
     * 启动
     *
     * @param swoole_websocket_server $server
     */
    public function onStart( swoole_websocket_server $server )
    {
        swoole_set_process_name( 'live-master' );
    }

    /**
     * 打开时候处理
     *
     * @param swoole_websocket_server $server
     * @param swoole_http_request     $request
     */
    public function onOpen( swoole_websocket_server $server, swoole_http_request $request )
    {
        // TODO: 打开链接
    }

    /**
     * 接收消息处理
     *
     * @param swoole_websocket_server $server
     * @param swoole_websocket_frame  $frame
     */
    public function onMessage( swoole_websocket_server $server, swoole_websocket_frame $frame )
    {
        $server->push( $frame->fd, "你发送的信息是：{$frame->data}" );
        // 投递任务
        $data = array(
            'task' => 1,
            'fd'   => $frame->fd
        );
        $server->task( $data );
    }

    /**
     * 启动监听
     *
     * @param \Swoole\Http\Server $server
     * @param int                 $worker_id
     */
    public function onWorkerStart( \Swoole\Http\Server $server, int $worker_id )
    {
        // 定义application目录
        define( 'APP_PATH', __DIR__ . '/../application/' );
        // 加载thinkphp系统文件
        require __DIR__ . '/../thinkphp/base.php';
    }

    /**
     * 客户端断开连接
     *
     * @param swoole_websocket_server $server
     * @param                         $fd
     */
    public function onClose( swoole_websocket_server $server, $fd )
    {
        // TODO: 断开连接
    }

    /**
     * 处理http请求
     *
     * @param swoole_http_request  $request
     * @param swoole_http_response $response
     */
    public function onRequest( swoole_http_request $request, swoole_http_response $response )
    {
        $_SERVER            = $_GET = $_POST = $_FILES = [];
        $_SERVER['argv'][0] = '';
        if ( isset( $request->server ) )
        {
            foreach ( $request->server as $key => $item )
            {
                $_SERVER[strtoupper( $key )] = $item;
            }
        }

        if ( isset( $request->files ) )
        {
            foreach ( $request->files as $key => $item )
            {
                $_FILES[$key] = $item;
            }
        }

        if ( isset( $request->header ) )
        {
            foreach ( $request->server as $key => $item )
            {
                $_SERVER[strtoupper( $key )] = $item;
            }
        }

        if ( isset( $request->get ) )
        {
            foreach ( $request->get as $key => $item )
            {
                $_GET[$key] = $item;
            }
        }

        if ( isset( $request->post ) )
        {
            foreach ( $request->post as $key => $item )
            {
                $_POST[$key] = $item;
            }
        }
        $_POST['http_server'] = $this->ws;
        // 可能需要注释Request.php 中path和pathinfo方法中的is_null($this->>pathinfo)
        ob_start();
        try
        {
            \think\Container::get( 'app', [ APP_PATH ] )->run()->send();
        }
        catch ( \Exception $e )
        {
            // $result = $e->getMessage();
        }
        $result = ob_get_contents();
        try
        {
            ob_end_clean();
        }
        catch ( Exception $e )
        {

        }
        $response->end( $result );
    }

    /**
     * 任务处理
     *
     * @param swoole_server $server
     * @param int           $task_id       任务号，从0开始
     * @param int           $src_worker_id 进程号
     * @param               $data          数据
     *
     * @return string
     */
    public function onTask( swoole_server $server, int $task_id, int $src_worker_id, $data )
    {
        $controller = isset( $data['controller'] ) ? '\\app\\common\\task\\' . ucfirst( $data['controller'] ) : '\\app\\common\\task\\Task';
        $obj        = new $controller();
        $method     = $data['method'] ?? '';
        if ( $method && method_exists( $obj, $method ) )
        {
            $flag = $obj->$method( $data['data'] );
        }
        else
        {
            // throw new \Exception( 'Not Found Method: ' . $method );
            return false;
        }

        return $flag;
    }

    /**
     * 任务执行完成触发
     *
     * @param swoole_server $serv
     * @param int           $task_id 任务号
     * @param string        $data    onTask return的数据
     */
    public function onFinish( swoole_server $serv, int $task_id, string $data )
    {
        echo 'finished - task' . PHP_EOL;
    }

    /**
     * 基础配置
     */
    public function set()
    {
        $this->ws->set( array(
            'log_level'             => 5,
            'enable_static_handler' => true,
            'document_root'         => '/home/wwwroot/johnxu.swoole.local.cn/thinkphp/public/static',
            'task_worker_num'       => 10, // 任务数量
            'worker_num'            => 4
        ) );
    }
}

new WebSocket();
